// WmDrv.cpp : implementation file
//

#include "stdafx.h"
#include "WmDrv.h"
#include "usb_wmDlg.h"


CWmClient::CWmClient()
{
	//m_buf=new u8[10240];
	m_bufindex=0;
}

CWmClient::~CWmClient()
{
	//delete m_buf;
}

//================================================================================
UINT ServerThread(LPVOID lparam)
{
	CWmDrv *pWmDrv=(CWmDrv *)lparam;
	DWORD ret;
	POSITION ps;
	u32 n=0;
	u32 i;
	CWmClientList *	 	pList;

	while(1)
	{
		char pbuf[100];
		
		sprintf_s(pbuf, "\r\n%s: %04d\r\n", "ServerThread", n++);  
		SendMessage(pWmDrv->m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
		pWmDrv->m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

		/*send out register packets*/
		pWmDrv->TxRegisterNotice();
		ret=WaitForSingleObject(pWmDrv->m_hEvent, pWmDrv->m_RegSlice); 
		pWmDrv->m_sstate=SRV_WAIT;
		pWmDrv->TxRegisterResult();

		for(i=0; i<3;i++)
		{
			pList=&(pWmDrv->m_ClientList[i]);
			for(ps=pList->GetHeadPosition(); ps; pList->GetNext(ps) )
			{       
				CWmClient &wmc = pList->GetAt(ps);
				pWmDrv->m_client=&wmc;
				pWmDrv->TxCheckNotice();

				ret=WaitForSingleObject(pWmDrv->m_hEvent, pWmDrv->m_ClientSlice[i]); 			
				if(ret==WAIT_OBJECT_0)	/*wm reply in his tick*/
				{
					if(pWmDrv->m_newrequst)
					{
						pWmDrv->m_newrequst=false;
						pWmDrv->TxDataRequest();
					}
				}
				//pWmDrv->TxQuickRespond();
			}

		}

		pWmDrv->FreshList();

		if(pWmDrv->m_exit)
		{
			pWmDrv->m_exit=false;
			break;
		}

		//Sleep(1000);

	}
	return 0;
}


// CWmDrv


CWmDrv::CWmDrv()
{

}

CWmDrv::CWmDrv(u32 rxad, u32 txad, u32 baud, u32 id,Cusb_wmDlg* pDlg,
					u32 RexMax, u32 ClientNum[], u32 ClientSlice[], u32 DataTmo,
					u32 RegSlice, u32 DataSlice,  u32 RetryMax, u32 idle
					)
{
	NetusbSetRxaddr(((u8)(rxad>>24)),((u8)(rxad>>16)),((u8)(rxad>>8)),((u8)(rxad)));
	NetusbSetTxaddr(((u8)(txad>>24)),((u8)(txad>>16)),((u8)(txad>>8)),((u8)(txad)));
	NetusbSetFrequence((u16)baud); //106->433

	m_rxad=rxad;
	m_txad=txad;
	m_pDlg=pDlg;
	m_serid=(u16)id;
	m_exit=false;
	m_sstate=SRV_WAIT;
	m_RexMax=RexMax;
	m_ClientNum[ITEM_H]=ClientNum[0];
	m_ClientNum[ITEM_M]=ClientNum[1];
	m_ClientNum[ITEM_L]=ClientNum[2];

	m_ClientSlice[ITEM_H]=ClientSlice[0];
	m_ClientSlice[ITEM_M]=ClientSlice[1];
	m_ClientSlice[ITEM_L]=ClientSlice[2];

	m_DataTmo=DataTmo;
	m_RegSlice=RegSlice;
	m_DataSlice=DataSlice;
	m_RetryMax=RetryMax;
	m_idle=idle;
	
	HANDLE hFile = CreateFile(_T("LogFile.txt"),
	GENERIC_WRITE, FILE_SHARE_READ,
	NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		AfxMessageBox(_T("Couldn't create the file!"));
	}
	else
	{
		// Attach a CFile object to the handle we have.
		m_pLogFile=new CFile(hFile);

		char pbuf[100];
		
		sprintf_s(pbuf, "\r\n%s\r\n", "Now we start the log....\r\n");  

		SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
		m_pLogFile->Write(pbuf, (u32)strlen(pbuf));


	}


}

CWmDrv::~CWmDrv()
{
	m_exit=true;
	CloseHandle(m_hEvent);
	m_pLogFile->Close();
	delete m_pLogFile;
}

void CWmDrv::StartUSBwm ()
{
	m_pause=true;
	m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	m_pThread=AfxBeginThread(ServerThread,this);
}

void CWmDrv::StopUSBwm ()
{
	m_exit=true;
}

void CWmDrv::PauseUSBwm ()
{
	if(m_pause)
	{
		m_pThread->SuspendThread();	
	}
	else
	{
		m_pThread->ResumeThread();
	}
	m_pause=!m_pause;
}

void CWmDrv::OnReceiveUSBMSG (WPARAM wParam, LPARAM lParam)
{
	BYTE* rb =(BYTE* )wParam;
	u32 n=(u32)lParam;

	m_pThread->SuspendThread();
	
	switch(m_sstate)
	{
		case SRV_REGISTER:
			RxClientRegister(rb);
			break;
		case SRV_RESPOND:
			RxClientRespond(rb);
			break;
		case SRV_DATA:
			RxClientData(rb, n);
			break;
		default:
			break;
	}
	m_pThread->ResumeThread();

	return;
}



void CWmDrv::TxRegisterNotice(void) 
{
	static u32 n=0;
	frame fm;

	fm.cmd=	CMD_TYPE(CMD, REG_TM);
	fm.did=0;		/*broadcast*/
	fm.sid=m_serid;

	NetusbSendData((BYTE *)(&fm), sizeof(fm));
	m_sstate=SRV_REGISTER;

	LogFrame(("TxRegisterNotice"), fm , n++);

}

void CWmDrv::TxRegisterResult(void) 
{
	POSITION ps;
	frame fm;

	if(m_newlogin==false)
	{
		return;
	}


	fm.cmd=	CMD_TYPE(RSP, REG_REP);
	fm.sid=m_serid;

	m_newlogin=false;
	
	for(ps=m_ClientList[ITEM_H].GetHeadPosition(); ps; m_ClientList[ITEM_H].GetNext(ps) )
	{       
		CWmClient &wmc = m_ClientList[ITEM_H].GetAt(ps);
		if(wmc.m_cstate==WM_REG)
		{
			fm.did=wmc.m_addr;
			NetusbSendData((BYTE *)(&fm), sizeof(fm));
			wmc.m_cstate=WM_ACTIVE;
			LogFrame(("TxRegisterResult"), fm , 0);

		}
	}
}

void CWmDrv::TxCheckNotice(void) 
{
	frame fm;

	fm.cmd=	CMD_TYPE(CMD, CHK_TM);
	fm.did=m_client->m_addr;
	fm.sid=m_serid;

	NetusbSendData((BYTE *)(&fm), sizeof(fm));
	m_sstate=SRV_RESPOND;
	LogFrame(("TxCheckNotice"), fm , 0);

}

void CWmDrv::TxDataRequest(void) 
{
	DWORD ret;
	u32 n=0;
	frame fm;
	static u32 i=0;
	char pbuf[100];
	
	m_tmo=false;

	m_pDlg->SetWMTimer(m_DataTmo);
	m_sstate=SRV_DATA;

	fm.did=m_client->m_addr;
	fm.sid=m_serid;

	do
	{
		fm.cmd=	n?(CMD_TYPE(NTC, REP_CMD)):(CMD_TYPE(NTC, DATA_CMD));
		NetusbSendData((BYTE *)(&fm), sizeof(fm));

		LogFrame(("TxDataRequest"), fm , n);

		ret=WaitForSingleObject(m_hEvent, m_DataSlice); 		
		if(ret==WAIT_TIMEOUT)
		{
			if(n<m_RetryMax)
			{
				n++;
			}
			else
			{
				sprintf_s(pbuf, "%s\r\n", "TxDataRequest: Slice data transfer time out");  
				SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
				m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

				m_pDlg->KillWMTimer();
				return;
			}
		}
		else
		{
			n=0;
		}

		if(m_client->m_over)
		{
			m_client->m_over=false;
			TxtoSocket();
			return;
		}

		m_tmo=m_pDlg->ChkWMTimer();

	}	while(!m_tmo);

	
	sprintf_s(pbuf, "%s\r\n", "TxDataRequest: Total data transfer time out");  
	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
	m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

}


void CWmDrv::TxQuickRespond(void) 
{
	frame fm;

	RxFromSocket();
	fm.cmd=	CMD_TYPE(RSP, BOOK_REP);
	fm.did=m_client->m_addr;
	fm.sid=m_serid;

	NetusbSendData((BYTE *)(&fm), sizeof(fm));

	LogFrame(("TxQuickRespond"), fm , 0);

}

void CWmDrv::RxClientRegister(BYTE* rb) 
{
	frame *fm=(frame *)rb;

	if((fm->did!=m_serid))
	{
		return;
	}


	switch(fm->cmd)
	{
		case CMD_TYPE(NTC, REG_REQ):	/*register request*/
			if((m_ClientNum[ITEM_H]+m_ClientNum[ITEM_M]+m_ClientNum[ITEM_L])<m_RexMax)	/*(active+idle)<30*/
			{
				CheckAndAdd(fm->sid);
			}
			else
			{
				GetIdleClient(fm->sid);
			}
			break;
		case CMD_TYPE(NTC, REG_CNL):	/*unregister request*/
			CheckAndDelete(fm->sid);
			break;
		default:
			break;

	}
	
}


void CWmDrv::RxClientRespond(BYTE* rb) 
{
	frame *fm=(frame *)rb;

	if(fm->cmd!=CMD_TYPE(RSP, CHK_REP))
	{
		return;
	}

	if((fm->sid!=m_client->m_addr)||(fm->did!=m_serid))
	{
		return;
	}
	m_client->m_over=false;
	m_client->m_actc=true;
	m_client->m_tm=GetTickCount()-m_client->m_tm;
	m_newrequst=true;
				
	SetEvent(m_hEvent);
	
	LogFrame(("RxClientRespond"), *fm , 0);

}

void CWmDrv::RxClientData(BYTE* rb, u32 n) 
{
	frame *fm=(frame *)rb;

	if((fm->cmd!=CMD_TYPE(RSP, DATA_REP))&&(fm->cmd!=CMD_TYPE(RSP, DATA_FNL)))
	{
		return;
	}

	if((fm->sid!=m_client->m_addr)||(fm->did!=m_serid))
	{
		return;
	}

	memcpy(m_client->m_buf+m_client->m_bufindex, rb, n);
	m_client->m_bufindex+=n;
	if(fm->cmd==CMD_TYPE(RSP, DATA_FNL))
	{
		m_sstate=SRV_WAIT;
		m_client->m_over=true;
				
		m_pDlg->KillWMTimer();

		LogFrame(("RxClientData: Last"), *fm , m_client->m_bufindex);
	}
	else
	{
		LogFrame(("RxClientData: Sub"), *fm ,m_client->m_bufindex);

	}
			
	SetEvent(m_hEvent);

}


void CWmDrv::TxtoSocket(void) 
{
	//m_client->m_buf[m_client->m_bufindex]=0;
	//CString str(m_client->m_buf);
//	m_pSocket->Send(str.GetBuffer(0),str.GetLength(),0);
	m_client->m_bufindex=0;

	char pbuf[100];
	sprintf_s(pbuf, ("TxtoSocket: A packet has received now!\r\n"));  
	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
	m_pLogFile->Write(pbuf, (u32)strlen(pbuf));


}

void CWmDrv::RxFromSocket(void) 
{

}



void CWmDrv::FreshList(void) 
{
	POSITION ps;
	char pbuf[100];
	
	u32 i;
	//CWmClient *p;
	CWmClient a;
	sprintf_s(pbuf, ("FreshList: ENTER\r\n"));  
	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
	m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

	for(i=0;i<3;i++)
	{
LOOP:

		for(ps=m_ClientList[i].GetHeadPosition(); ps; m_ClientList[i].GetNext(ps) )
		{       
			CWmClient &wmc = m_ClientList[i].GetAt(ps);

			if(wmc.m_actc)
			{
				wmc.m_actc=false;
				wmc.m_cstate=WM_ACTIVE;
				wmc.m_tm=0;
				if(i!=ITEM_H)
				{
					//p=new CWmClient();
					//memcpy(&a, &wmc,sizeof(CWmClient));
					m_ClientList[ITEM_H].AddTail(wmc);
					//m_ClientList[i].GetPrev(ps1);
					m_ClientList[i].RemoveAt(ps);
					//ps=ps1;
					m_ClientNum[i]-=1;
					m_ClientNum[ITEM_H]+=1;

					sprintf_s(pbuf, ("FreshList: GOTO0\r\n"));  
					SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
					m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

					goto LOOP;/*MAKE SURE: RemoveAt() will change the list, so you have to do it from first*/
				}

			}
			else if(wmc.m_tm<(s32)m_idle)
			{
				wmc.m_cstate=WM_IDLE;
				if(i!=ITEM_M)
				{
					//memcpy(&a, &wmc,sizeof(CWmClient));
					m_ClientList[ITEM_M].AddTail(wmc);
					//m_ClientList[i].GetPrev(ps1);
					m_ClientList[i].RemoveAt(ps);
					//ps=ps1;
					m_ClientNum[i]-=1;
					m_ClientNum[ITEM_M]+=1;
					sprintf_s(pbuf, ("FreshList: GOTO1\r\n"));  
					SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
					m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

					goto LOOP;

				}
			}
			else
			{
				wmc.m_cstate=WM_INACTIVE;
				if(i!=ITEM_L)
				{
					//memcpy(&a, &wmc,sizeof(CWmClient));
					m_ClientList[ITEM_L].AddTail(wmc);
					//m_ClientList[i].GetPrev(ps1);
					m_ClientList[i].RemoveAt(ps);
					//ps=ps1;
					m_ClientNum[i]-=1;
					m_ClientNum[ITEM_L]+=1;
					sprintf_s(pbuf, ("FreshList: GOTO2\r\n"));  
					SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
					m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

					goto LOOP;

				}
			}
		}


	}
	sprintf_s(pbuf, ("FreshList: EXIT\r\n"));  
	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
	m_pLogFile->Write(pbuf, (u32)strlen(pbuf));


	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)0, true);

}


bool CWmDrv::CheckAndAdd(u16 wmid) 
{
	POSITION ps;
	CWmClient * pClient;
	bool n=false;
	u32 i;

	char pbuf[100];

	/*Check if this wm is already registered*/
	for(i=0; i<3; i++)
	{
		for(ps=m_ClientList[i].GetHeadPosition(); ps; m_ClientList[i].GetNext(ps) )
		{       
			CWmClient &wmc  = m_ClientList[i].GetAt(ps);
			if(wmc.m_addr==wmid)
			{
				n=true;
				wmc.m_actc=true;	/*this guy can be set to active*/
				wmc.m_tm=GetTickCount()-wmc.m_tm;

				sprintf_s(pbuf, ("CheckAndAdd  wm%02d has registered already\r\n"), wmid);  
				SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
				m_pLogFile->Write(pbuf, (u32)strlen(pbuf));				
				break;
			}
		}
	}


	if(!n)	/*new guy*/
	{
		pClient = new CWmClient();
		pClient->m_addr=wmid;
		pClient->m_tm=0;
		pClient->m_cstate=WM_REG;
		pClient->m_actc=true;
		/*set the flag that thread will call TxRegisterResult() to reply register OK*/
		m_newlogin=true; 
		m_ClientList[ITEM_H].AddTail(*pClient);
		m_ClientNum[ITEM_H]+=1;

		sprintf_s(pbuf, ("CheckAndAdd  wm%02d has registered now\r\n"), wmid);  
		SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
		m_pLogFile->Write(pbuf, (u32)strlen(pbuf));
	}

	return true;
}

void CWmDrv::GetIdleClient(u16 wmid) 
{
	POSITION ps;
	CWmClient * pClient;
	bool n=false;
	u32 i;

	char pbuf[100];

	/*Check if this wm is already registered*/
	for(i=0; i<3; i++)
	{
		for(ps=m_ClientList[i].GetHeadPosition(); ps; m_ClientList[i].GetNext(ps) )
		{       
			CWmClient &wmc  = m_ClientList[i].GetAt(ps);
			if(wmc.m_addr==wmid)
			{
				n=true;
				wmc.m_actc=true;	/*this guy can be set to active*/
				wmc.m_tm=GetTickCount()-wmc.m_tm;

				sprintf_s(pbuf, ("CheckAndAdd  wm%02d has registered already\r\n"), wmid);  
				SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
				m_pLogFile->Write(pbuf, (u32)strlen(pbuf));				
				break;
			}
		}
	}

	if(m_ClientNum[ITEM_L]<=0)
	{
		return;
	}

	m_ClientList[ITEM_L].RemoveHead();
	m_ClientNum[ITEM_L]-=1;

	if(!n)	/*new guy*/
	{
		pClient = new CWmClient();
		pClient->m_addr=wmid;
		pClient->m_tm=0;
		pClient->m_cstate=WM_REG;
		pClient->m_actc=true;
		/*set the flag that thread will call TxRegisterResult() to reply register OK*/
		m_newlogin=true; 
		m_ClientList[ITEM_H].AddTail(*pClient);
		m_ClientNum[ITEM_H]+=1;

		sprintf_s(pbuf, ("CheckAndAdd  wm%02d has registered now\r\n"), wmid);  
		SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
		m_pLogFile->Write(pbuf, (u32)strlen(pbuf));
	}

	return ;
}


bool CWmDrv::CheckAndDelete(u16 wmid) 
{
	POSITION ps;
	u32 i;

	for(i=0;i<3;i++)
	{
		for(ps=m_ClientList[i].GetHeadPosition(); ps; m_ClientList[i].GetNext(ps) )
		{       
			CWmClient &wmc  = m_ClientList[i].GetAt(ps);
			if(wmc.m_addr==wmid)
			{
				m_ClientList[i].RemoveAt(ps);
				m_ClientNum[i]-=1;
				char pbuf[100];
				sprintf_s(pbuf, ("CheckAndDelete  wm%02d has deleted now\r\n"), wmid);  
				SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
				m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

				return true;
			}
		}
	}
	
	return false;
}

void CWmDrv::LogFrame(char * fn, frame fm, u32 n)
{
	char pbuf[100];

	sprintf_s(pbuf, ("%s  %04d, did=%02d, sid=%02d, cmd=0X%02X\r\n"), fn, n, fm.did, fm.sid, fm.cmd);  
	SendMessage(m_pDlg->m_hwnd,WM_UPDATEDATA, (WPARAM)pbuf, false);
	m_pLogFile->Write(pbuf, (u32)strlen(pbuf));

}

void CWmDrv::SetParameters(u32 RexMax, u32 ClientNum[], u32 ClientSlice[], u32 DataTmo,
					u32 RegSlice, u32 DataSlice,  u32 RetryMax, u32 idle) 
{
	m_pThread->SuspendThread();

	m_RexMax=RexMax;
	m_RegSlice=RegSlice;
	
	m_ClientNum[ITEM_H]=ClientNum[0];
	m_ClientNum[ITEM_M]=ClientNum[1];
	m_ClientNum[ITEM_L]=ClientNum[2];

	m_ClientSlice[ITEM_H]=ClientSlice[0];
	m_ClientSlice[ITEM_M]=ClientSlice[1];
	m_ClientSlice[ITEM_L]=ClientSlice[2];

	m_DataTmo=DataTmo;

	m_DataSlice=DataSlice;

	m_RetryMax=RetryMax;

	m_pThread->ResumeThread();

}


// CWmDrv message handlers
